package a

import (
	"fmt"
	"reflect"
	"regexp"
	"strings"

	"github.com/iancoleman/strcase"
)

func A是常规字段(字段 *S字段) bool {
	return 字段.A类型 != A字段类型_关联字段 &&
		!字段.A是外键 &&
		字段.A类型 != A字段类型_join &&
		字段.A类型 != ""
}

func A取一对一或多的关联元件(字段 *S字段) (关联元件 *S元件) {
	if 字段.A类型 == A字段类型_关联字段 {
		关联类型, 关联元件 := A解关联属性(字段)
		if 关联类型 != A关联类型_属于 {
			return 关联元件
		}
	}
	return nil
}

func A解关联属性(字段 *S字段) (关联类型 string, 关联元件 *S元件) {
	属性 := A解对象(字段.A关联属性)
	关联id := 属性["关联id"]
	关联类型 = 属性["关联类型"]
	关联元件 = A元件集[关联id]
	return
}

func A解join属性(字段 *S字段) (关联元件 *S元件, join源字段 *S字段, 关联字段 *S字段) {
	父元件 := A元件集[字段.A父id]
	属性 := A解对象(字段.Ajoin属性)
	关联字段名 := 属性["关联字段名"]
	关联字段 = A字段集[A成字段id_从元件(父元件, 关联字段名)]
	_, 关联元件 = A解关联属性(关联字段)

	join源字段名 := 属性["join源字段名"]
	join源字段 = A字段集[A成字段id_从元件(关联元件, join源字段名)]

	return
}

func A解链接字段(字段 *S字段) (关联元件 *S元件, 显示值字段名 string) {
	id, 字段名 := A拆分字段id(字段.A候选值源字段)
	关联元件 = A元件集[id]
	显示值字段名 = 字段名
	return
}

func A取元件_从元件名(父元件 *S元件, 元件名 string) (元件 *S元件) {
	元件 = A元件集[A成id(父元件.Aid, 元件名)]
	return
}

func A取外键关联元件(字段 *S字段) (关联元件 *S元件) {
	关联id := A成id(字段.A关联元件名, 字段.A关联元件名)
	关联元件 = A元件集[关联id]
	return
}

func A打印models(models any) {
	modelsValue := A取反射el(reflect.ValueOf(models))
	if modelsValue.Kind() == reflect.Slice {
		for i := 0; i < modelsValue.Len(); i++ {
			element := modelsValue.Index(i)
			if element.Kind() == reflect.Ptr {
				element = element.Elem()
			}
			fmt.Printf("%d: %+v\n", i, element.Interface())
		}
	}
}

// func A成model全名(元件 *S元件) (res string) {
// 	res = 元件.A元件名 + "." + A成model名_go(元件)
// 	元件.Amodel英文全名 = res
// 	return
// }

func A成model名(元件 *S元件) (res string) {
	// res = 元件.A元件名 + "_" + 元件.A名称 + "model"
	// res = 元件.A元件名 + "之" + 元件.A名称 + "model"
	// res = 元件.A名称 + "model"
	res = strings.ReplaceAll(元件.Aid, ".", "之") + "model"
	return
}

func A成model名_go(元件 *S元件) (res string) {
	// res = "S" + 元件.A元件名 + "_" + 元件.A名称 + "model"
	元件.Amodel名 = A成model名(元件)
	res = "M" + 元件.Amodel名
	元件.Amodel英文名 = res

	// 元件.Amodel英文全名 = 元件.A元件英文名 + "." + 元件.Amodel英文名
	元件.Amodel英文全名 = "aa_model" + "." + 元件.Amodel英文名
	// 元件.Amodel英文全名 = 元件.A英文名 + "." + 元件.Amodel英文名
	return
}

func A成表名(元件 *S元件) {
	if 元件.A表名 == "" {
		// 元件.A表名 = 元件.A父id + "_" + 元件.A名称
		元件.A表名 = strings.ReplaceAll(元件.Aid, ".", "_")
	}
}

func A成父id(父元件 *S元件, 元件 *S元件) (res string) {
	上层id := ""
	if 父元件 != nil {
		上层id = 父元件.Aid
	}
	res = 上层id + "." + 元件.A英文名
	元件.A包路径 = res
	return
}

// func A成包路径(父元件 *S元件, 元件 *S元件) (res string) {
// 	上层路径 := "server/aa"
// 	if 父元件 != nil {
// 		上层路径 = 父元件.A包路径
// 	}
// 	res = 上层路径 + "/" + 元件.A英文名
// 	元件.A包路径 = res
// 	return
// }

// func A成表名(元件名 string, 元件名 string) (res string) {
// 	res = 元件名 + "_" + 元件名
// 	return
// }

func A成字段id_从元件(元件 *S元件, 字段名 string) (id string) {
	// id = 元件名 + "." + 元件名 + "." + 字段名
	return A成字段id(元件.Aid, 字段名)
}

func A成字段id(id string, 字段名 string) (res string) {
	res = id + "." + 字段名
	return
}

func A予id(父元件 *S元件, 元件 *S元件) {
	// 上层路径 := "server/aa"
	// if 父元件 != nil {
	// 	上层路径 = 父元件.A包路径
	// }

	if 父元件 != nil {
		元件.A父id = 父元件.Aid

		元件.Aid = A成id(父元件.Aid, 元件.A名称)
		元件.A英文id = A成英文id(父元件.A英文id, 元件.A英文名)
	} else {
		元件.Aid = 元件.A名称
		元件.A英文id = 元件.A英文名
	}
	元件.A包路径 = A包根路径 + "/" + 元件.A英文id
}

func A成英文id(父英文id string, 元件英文名 string) (id string) {
	id = 父英文id + "/" + 元件英文名
	return
}

func A成id(父id string, 元件名 string) (id string) {
	id = 父id + "." + 元件名
	return
}

func A取字段(str string) (元件 *S元件, 字段 *S字段) {
	id, 字段id := A拆分并合成字段id(str)
	元件 = A元件集[id]
	字段 = A字段集[字段id]
	return
}

func A拆分并合成字段id(str string) (id string, 字段id string) {
	id, 字段名 := A拆分字段id(str)
	字段id = A成字段id(id, 字段名)
	return
}

func A拆分字段id(str string) (id string, 字段名 string) {
	lastDotIdx := strings.LastIndex(str, ".")
	if lastDotIdx == -1 {
		// 没有"."时，id为原字符串，字段名为空
		id = str
		字段名 = ""
		return
	}
	// 截取最后一个"."前后的内容
	id = str[:lastDotIdx]
	字段名 = str[lastDotIdx+1:]
	return
}

func A拆分id(str string) (split []string) {
	split = strings.Split(str, ".")
	return
}

func A成字段名称(字段 *S字段) {
	if 字段.A名称go == "" {
		// 1. 判断是否以中文开头
		reg := regexp.MustCompile(`^[\p{Han}]`)
		if reg.MatchString(字段.A名称) {
			字段.A名称go = "A" + 字段.A名称
			字段.A名称sql = 字段.A名称
		} else {
			// 2. 非中文开头：驼峰转下划线
			小写 := strcase.ToSnake(字段.A名称)
			// 大驼峰 := strcase.ToCamel(字段.A名称)
			大驼峰 := AToCamel(字段.A名称)
			字段.A名称go = 大驼峰
			字段.A名称sql = 小写
		}
	}
}

func A取字段名称go(str string) (字段名称go string) {
	// 1. 判断是否以中文开头
	reg := regexp.MustCompile(`^[\p{Han}]`)
	if reg.MatchString(str) {
		字段名称go = "A" + str
	} else {
		// 2. 非中文开头：驼峰转下划线
		// 大驼峰 := strcase.ToCamel(str)
		大驼峰 := AToCamel(str)
		字段名称go = 大驼峰
	}
	return
}
